/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package rentcar.services;

import com.google.gson.Gson;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import rentcar.datareceiver.Application;
import rentcar.datareceiver.DbSettings_Container;
import rentcar.datareceiver.models.CarPosData;
import rentcar.datareceiver.models.CarPosInfo;
import rentcar.datareceiver.models.CmdResultInfo;

/**
 * 该类为多线程类，用于服务端
 */
public class ServerThread implements Runnable {

        private final static String QUEUE_NAME = "hello";
        ////final static String MQ_HOST="127.0.0.1";
        final static String MQ_HOST = "rabbitmq";
        final static Integer MQ_PORT = 5672;
        //String DB_URL = "jdbc:mysql://localhost:3306/rentcar", DB_USER = "root", DB_PASSWD = "root";
        String DB_URL = "jdbc:mysql://mysqlrecv:3306/rentcar", DB_USER = "root", DB_PASSWD = "root";
        private Socket client = null;
        AmqpTemplate template = null;
        java.sql.Connection connection = null;
        Statement stmt = null;
        //DbSetting ds=new DbSetting();
        //DbSettings_Container ds = new DbSettings_Container();

        public ServerThread(Socket client) {
                this.client = client;
                MqInit();
                DbConnInit();
        }

        boolean SocketIsConnected(Socket socket) {
                try {
                        socket.sendUrgentData(0xFF);
                        return true;
                } catch (Exception ex) {
                        return false;
                }
        }

        /*
        void MqInit() {
                org.springframework.amqp.rabbit.connection.ConnectionFactory connectionFactory = new CachingConnectionFactory();

                AmqpAdmin admin = new RabbitAdmin(connectionFactory);
                admin.declareQueue(new Queue(QUEUE_NAME));
                template = new RabbitTemplate(connectionFactory);
                System.out.println("Sending message to " + QUEUE_NAME);
        }
         */
        void MqInit() {
                //String MQ_HOST=ms.getHost(),QUEUE_NAME=ms.getQueue();
                //Integer MQ_PORT=ms.getPort();

                org.springframework.amqp.rabbit.connection.ConnectionFactory connectionFactory
                        = new CachingConnectionFactory(MQ_HOST, MQ_PORT);

                AmqpAdmin admin = new RabbitAdmin(connectionFactory);
                admin.declareQueue(new Queue(QUEUE_NAME));
                template = new RabbitTemplate(connectionFactory);

        }

        void DbConnInit() {
                //String DB_URL = ds.getUrl(), DB_USER = ds.getUser(), DB_PASSWD = ds.getPasswd();
                try {
                        connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWD);
                        stmt = connection.createStatement();
                } catch (SQLException ex) {
                        Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
                }
        }

        //处理通信细节的静态方法，这里主要是方便线程池服务器的调用  
        public void execute(Socket client) {
                try {
                        if (client == null || !SocketIsConnected(client)) {
                                System.out.println("Got closed client!");
                                return;
                        }
                        //获取Socket的输出流，用来向客户端发送数据    
                        PrintStream out = new PrintStream(client.getOutputStream());
                        //获取Socket的输入流，用来接收从客户端发送过来的数据  
                        BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream()));
                        boolean flag = true;
                        //超过10秒不发送数据则关闭
                        long lStartNull = 0, lNow = 0, MaxStep = 60000;

                        while (flag) {
                                if (client == null || !SocketIsConnected(client)) {
                                        System.out.println("client closed!");
                                        break;
                                }
                                System.out.println("receiving data...");
                                //接收从客户端发送过来的数据   
                                String str = buf.readLine();
                                if (str != null && !"".equals(str)) {
                                        lStartNull = 0;
                                        System.out.println("Processing data stated");
                                        ProcessData(str);
                                        //发送到对应的客户端    
                                        //out.println("message received: " + str);

                                } else {
                                        if (lStartNull == 0) {
                                                lStartNull = (new Date()).getTime();
                                        }
                                        lNow = (new Date()).getTime();
                                        if (lNow - lStartNull > MaxStep && client.getInputStream().read() == -1) {
                                                System.out.println(" connection lost ...");
                                                break;
                                        }
                                }
                        }
                        out.close();
                        buf.close();
                        client.close();
                        client = null;
                        System.out.println("client closed!");
                } catch (Exception e) {
                        System.out.println("Process error!" + e.getMessage());
                }
        }

        @Override
        public void run() {
                execute(client);
        }

        String GetIdentify(String strData) {
                //获取消息标识，区分位置数据和开关门操作返回值
                String identify = "";
                int startIndex = strData.indexOf("identifying");
                char[] charArray = strData.toCharArray();
                boolean begin = false, end = false, omit = false;
                for (int i = startIndex; i < charArray.length; i++) {
                        omit = false;
                        switch (charArray[i]) {
                                case ':':
                                        begin = true;
                                        omit = true;
                                        break;
                                case ',':
                                case '}':
                                        end = true;
                                        break;
                                case '"':
                                        omit = true;
                                        break;
                                default:
                                        break;
                        }

                        if (end) {
                                break;
                        }

                        if (begin && !omit) {
                                identify += String.valueOf(charArray[i]);
                        }
                }
                return identify;
        }

        void ProcessData(String strData) {
                Application.g_DoorSucceed = false;
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String strtime = df.format(new Date());;
                System.out.println("--- " + strtime + " ---  received: " + strData);
//解析
                String identifying = GetIdentify(strData);
                Gson gson = new Gson();

                if ("E02".equals(identifying)) {
                        //位置信息
                        /*
                        CarPosData tpd = (CarPosData) tp.getData();
                        //经纬度除以1e6
                        tpd.setLon(tpd.getLon() / 1e6);
                        tpd.setLat(tpd.getLat() / 1e6);
//速度除以10
                        tpd.setSpeed(tpd.getSpeed() / 10);
//存数据库
                        tp.setData(tpd);
                         */
                        CarPosInfo cpi = gson.fromJson(strData, CarPosInfo.class);
                        System.out.println("Got position data, save them to database");
                        SaveToDb(cpi);
//发送至消息总线
                        SendToMQ(strData);
                } else if ("E03".equals(identifying)) {
                        //指令应答
                        System.out.println("Got execution result, updating g_DoorSucceed.");
                        CmdResultInfo cri = gson.fromJson(strData, CmdResultInfo.class);
                        Application.g_DoorSucceed = cri.getData().getResult() == 0;
                }

        }

        void SendToMQ(String strData) {
                if (template == null) {
                        System.out.println("rabbitTemplate is null!");
                } else {
                        template.convertAndSend(QUEUE_NAME, strData);
                }
        }

        void SaveToDb(CarPosInfo tp) {

                if (tp == null) {
                        System.out.println("CarPosInfo is null!");
                        return;
                }
                CarPosData cpd = (CarPosData) tp.getData();

                try {
                        String sql = String.format("insert into posdata(systemno,identifying,time,latitude,longitude,speed,direction,islocation) values('%s','%s','%s',%f,%f,%f,%f,%d)",
                                tp.getSystemno(), tp.getIdentifying(), cpd.getTime(), cpd.getLat(), cpd.getLon(), cpd.getSpeed(), cpd.getDirection(), cpd.getIslocation());

                        // System.out.println(sql);
                        stmt.executeUpdate(sql);
                        System.out.println("write data to database!");
                } catch (SQLException e) {
                        throw new IllegalStateException("Cannot connect the database!", e);
                }

        }
}
